package com.hcnetsdk.jna;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

import com.hikvision.netsdk.HCNetSDK;
import com.hikvision.netsdk.NET_DVR_DEVICEINFO_V30;
import com.hikvision.netsdk.NET_DVR_PREVIEWINFO;
import com.hikvision.netsdk.RealPlayCallBack;

import org.MediaPlayer.PlayM4.Player;
import org.MediaPlayer.PlayM4.PlayerCallBack;

/**
 * 画面显示可能影响腾讯显示
 *
 PlaySurfaceView playView;
 int switchCamera = 0;

 public void switchIPC() {
 if (switchCamera == 0) {
 startIPC();
 switchCamera = 1;
 } else {
 stopIPC();
 switchCamera = 0;
 }
 }

 public void startIPC() {
 trtcCloud.stopLocalPreview();//


 trtcCloud.enableCustomVideoCapture(true);
 if (playView == null) {
 DisplayMetrics metric = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(metric);
 playView = new PlaySurfaceView(this);
 playView.setM_iWidth(metric.widthPixels);
 playView.setM_iHeight(metric.heightPixels);
 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
 params.gravity = Gravity.CENTER;
 addContentView(playView, params);
 //cpv = (CameraPreview) findViewById(R.id.view_ca);
 playView.setVisibility(View.VISIBLE);
 playView.setIpcDataFunc(new PlaySurfaceView.IIpcDataFunc() {
@Override
public void afterCall(int dataLen, byte[] data, int nWidth, int nHeight, int nFrameTime) {
if (trtcCloud != null) {
TRTCCloudDef.TRTCVideoFrame var1 = new TRTCCloudDef.TRTCVideoFrame();
var1.pixelFormat = TRTCCloudDef.TRTC_VIDEO_PIXEL_FORMAT_I420;
var1.data = data;
var1.height = nWidth;
var1.width = nHeight;
var1.timestamp = nFrameTime;
trtcCloud.sendCustomVideoData(var1); //todo trtcsdk腾讯音视频接入ipc，未显示本地
} else {
Log.d(TAG, "sdk setIpcDataFunc trtcCloud==null");
}
}
});
 }
 new Thread(new Runnable() {
@Override
public void run() {
playView.startPreview();
}

}).start();

 }

 public void stopIPC() {
 if (playView != null) {
 playView.setVisibility(View.INVISIBLE);
 playView.stopPreview();
 playView = null;
 }
 if (trtcCloud != null) {
 trtcCloud.enableCustomVideoCapture(false);

 TXCloudVideoView localVideoView = mVideoViewLayout.getCloudVideoViewByIndex(1);
 localVideoView.setUserId(trtcParams.userId);
 localVideoView.setVisibility(View.VISIBLE);
 trtcCloud.setLocalViewFillMode(TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FILL);
 trtcCloud.startLocalPreview(true, localVideoView);
 }
 }
 */
@SuppressLint("NewApi")
public class PlaySurfaceViewTestTRTC extends SurfaceView implements Callback {

    private final String TAG = "PlaySurfaceView";
    private int m_iWidth = 0;
    private int m_iHeight = 0;

    public int getM_iWidth() {
        return m_iWidth;
    }

    public void setM_iWidth(int m_iWidth) {
        this.m_iWidth = m_iWidth;
    }

    public int getM_iHeight() {
        return m_iHeight;
    }

    public void setM_iHeight(int m_iHeight) {
        this.m_iHeight = m_iHeight;
    }

    public int m_iPreviewHandle = -1;
    public SurfaceHolder m_hHolder;
    public boolean bCreate = false;
    public int m_lUserID = -1;
    public int m_iChan = 0;

    private int m_iPort = -1;
    private boolean m_bSurfaceCreated = false;

    public PlaySurfaceViewTestTRTC(Activity demo) {
        super(demo);

        m_hHolder = this.getHolder();
        getHolder().addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
        m_hHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        System.out.println("surfaceChanged");
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        bCreate = true;
        System.out.println("surfaceCreated");
        // new add
        m_bSurfaceCreated = true;
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        if (-1 == m_iPort) {
            return;
        }
        Surface surface = holder.getSurface();
        if (surface.isValid()) {
            if (!Player.getInstance().setVideoWindow(m_iPort, 0, holder)) {
                Log.e(TAG, "Player setVideoWindow failed!");
            }
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        System.out.println("surfaceDestroyed");
        bCreate = false;

        // new add
        m_bSurfaceCreated = false;
        if (-1 == m_iPort) {
            return;
        }
        Surface surface = holder.getSurface();
        if (surface.isValid()) {
            if (!Player.getInstance().setVideoWindow(m_iPort, 0, null)) {
                Log.e(TAG, "Player setVideoWindow failed!");
            }
        }
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.setMeasuredDimension(m_iWidth - 1, m_iHeight - 1);
    }


    public void stopPreview() {
        stopPlayer();

        HCNetSDK.getInstance().NET_DVR_StopRealPlay(m_iPreviewHandle);
        HCNetSDK.getInstance().NET_DVR_Logout_V30(m_lUserID);

        // release net SDK resource
        HCNetSDK.getInstance().NET_DVR_Cleanup();

    }

    public void startPreview() {
        setCameraInfo();
        HCNetSDK.getInstance().NET_DVR_Init();
        m_lUserID = loginNormalDevice();
        if (m_lUserID < 0) return;

        Log.i(TAG, "preview channel:" + m_iChan);
        while (!bCreate) {
            try {
                Thread.sleep(100);
                Log.i(TAG, "wait for surface create");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
//----- new add
        RealPlayCallBack fRealDataCallBack = getRealPlayerCbf();
        if (fRealDataCallBack == null) {
            Log.e(TAG, "fRealDataCallBack object is failed!");
            return;
        }
        Log.i(TAG, "preview channel:" + m_iChan);
//-----
        NET_DVR_PREVIEWINFO previewInfo = new NET_DVR_PREVIEWINFO();
        previewInfo.lChannel = m_iChan;
        previewInfo.dwStreamType = 1; //1 substream 0 main
        previewInfo.bBlocked = 1;
        previewInfo.hHwnd = m_hHolder;

        // HCNetSDK start preview
        m_iPreviewHandle = HCNetSDK.getInstance().NET_DVR_RealPlay_V40(m_lUserID, previewInfo, fRealDataCallBack);
        if (m_iPreviewHandle < 0) {
            Log.e(TAG, "NET_DVR_RealPlay is failed!Err:" + HCNetSDK.getInstance().NET_DVR_GetLastError());
        }
    }

    private CameraInfo camera;

    public class CameraInfo {
        public int id;
        public String address;
        public int port;
        public String account;
        public String password;
        public String name;
    }


    private void setCameraInfo() {
        camera = new CameraInfo();
        camera.id = 100;
        camera.address = "192.168.0.100";
        camera.port = 8000;
        camera.account = "admin";
        camera.password = "ss123456";
        camera.name = "admin";
    }

    private int loginNormalDevice() {
        // get instance
        NET_DVR_DEVICEINFO_V30 m_oNetDvrDeviceInfoV30 = null;
        m_oNetDvrDeviceInfoV30 = new NET_DVR_DEVICEINFO_V30();
        if (null == m_oNetDvrDeviceInfoV30) {
            Log.e(TAG, "HKNetDvrDeviceInfoV30 new is failed!");
            return -1;
        }

        String strIP = camera.address;
        int nPort = camera.port;
        String strUser = camera.account;
        String strPsd = camera.password;
        // call NET_DVR_Login_v30 to login on, port 8000 as default
        int iLogID = HCNetSDK.getInstance().NET_DVR_Login_V30(strIP, nPort,
                strUser, strPsd, m_oNetDvrDeviceInfoV30);
        if (iLogID < 0) {
            Log.e(TAG, "NET_DVR_Login is failed!Err:"
                    + HCNetSDK.getInstance().NET_DVR_GetLastError());
            return -1;
        }
        int iStartChan = -1;
        int iChanNum = 0;
        if (m_oNetDvrDeviceInfoV30.byChanNum > 0) {
            iStartChan = m_oNetDvrDeviceInfoV30.byStartChan;
            iChanNum = m_oNetDvrDeviceInfoV30.byChanNum;
        } else if (m_oNetDvrDeviceInfoV30.byIPChanNum > 0) {
            iStartChan = m_oNetDvrDeviceInfoV30.byStartDChan;
            iChanNum = m_oNetDvrDeviceInfoV30.byIPChanNum
                    + m_oNetDvrDeviceInfoV30.byHighDChanNum * 256;
        }
        m_iChan = iStartChan;
        Log.i(TAG, "NET_DVR_Login is Successful!");

        return iLogID;
    }

    private void stopPlayer() {
        Player.getInstance().stopSound();
                // player stop play
        if (!Player.getInstance().stop(m_iPort)) {
            Log.e(TAG, "stop is failed!");
            return;
        }
        Player.getInstance().setDecodeCB(m_iPort,null);

        if (!Player.getInstance().closeStream(m_iPort)) {
            Log.e(TAG, "closeStream is failed!");
            return;
        }
        if (!Player.getInstance().freePort(m_iPort)) {
            Log.e(TAG, "freePort is failed!" + m_iPort);
            return;
        }

        m_iPort = -1;
    }

    private RealPlayCallBack getRealPlayerCbf() {
        RealPlayCallBack cbf = new RealPlayCallBack() {

            public void fRealDataCallBack(int iRealHandle, int iDataType, byte[] pDataBuffer, int iDataSize) {

                processRealData(1, iDataType, pDataBuffer, iDataSize, Player.STREAM_REALTIME);
            }
        };
        return cbf;
    }

    private void processRealData(int iPlayViewNo, int iDataType, byte[] pDataBuffer,
                                 int iDataSize, int iStreamMode) {
        //   Log.i(TAG, "iPlayViewNo:" + iPlayViewNo + ",iDataType:" + iDataType + ",iDataSize:" + iDataSize);
        if (HCNetSDK.NET_DVR_SYSHEAD == iDataType) {
            if (m_iPort >= 0) {
                return;
            }
            m_iPort = Player.getInstance().getPort();
            if (m_iPort == -1) {
                Log.e(TAG, "getPort is failed with: " + Player.getInstance().getLastError(m_iPort));
                return;
            }
            Log.i(TAG, "getPort succ with: " + m_iPort);
            if (iDataSize > 0) {
                if (!Player.getInstance().setStreamOpenMode(m_iPort, iStreamMode))  //set stream mode
                {
                    Log.e(TAG, "setStreamOpenMode failed");
                    return;
                }

                if (!Player.getInstance().openStream(m_iPort, pDataBuffer, iDataSize, 2 * 1024 * 1024)) //open stream
                {
                    Log.e(TAG, "openStream failed");
                    return;
                }
                while (!m_bSurfaceCreated) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    Log.i(TAG, "wait 100 for surface, handle:" + iPlayViewNo);
                }
                setDecodeCB();//设置解码回调
                if (!Player.getInstance().play(m_iPort, getHolder())) {
                    Log.e(TAG, "play failed,error:" + Player.getInstance().getLastError(m_iPort));
                    return;
                }
                if (!Player.getInstance().playSound(m_iPort)) {
                    Log.e(TAG, "playSound failed with error code:" + Player.getInstance().getLastError(m_iPort));
                    return;
                }
            }
        } else {
            if (!Player.getInstance().inputData(m_iPort, pDataBuffer, iDataSize)) {
                Log.e(TAG, "inputData failed with: " + Player.getInstance().getLastError(m_iPort));
            }
        }
    }


    private IIpcDataFunc callback;

    public void setIpcDataFunc(IIpcDataFunc funcData) {
        callback = funcData;
    }

    public interface IIpcDataFunc {
        void afterCall(int dataLen, byte[] data, int nWidth, int nHeight, int nFrameTime);
    }

    private void setDecodeCB() {
        Player.getInstance().setDecodeCB(m_iPort, new PlayerCallBack.PlayerDecodeCB() {

            @Override
            public void onDecode(int nPort, final byte[] data,
                                 int nDataLen, int nWidth, int nHeight, int nFrameTime,
                                 int nDataType, int arg7) {
                try {
                    if (nDataType == 3) {
                        byte[] i420bytes;
                        i420bytes = swapYV12toI420(data, nWidth, nHeight);
                        if (i420bytes != null) {
                            callback.afterCall(i420bytes.length, i420bytes, nWidth, nHeight, nFrameTime);
                        }
                    }

                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
            }

        });

    }

    private byte[] i420bytes = null;

    private byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
        if (null == i420bytes) {
            i420bytes = new byte[yv12bytes.length];
        }
        int nTemp = width * height;
        System.arraycopy(yv12bytes, nTemp + (nTemp / 4), i420bytes, nTemp, nTemp / 4);
        System.arraycopy(yv12bytes, nTemp, i420bytes, nTemp + (nTemp / 4), nTemp / 4);
        System.arraycopy(i420bytes, nTemp, yv12bytes, nTemp, nTemp / 2);

        return yv12bytes;
    }

}
